<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>状态监控</title>
  <link href="../../css/index.css" rel="stylesheet">
  <style>
    .drawer-content {
      display: block;
    }

    .time-contorl-content {
      /* display: flex; */
      margin: 20px 10px;
    }

    .time-item {
      display: flex;
      margin: 0 10px;
    }

    .time-show {
      margin: 0 20px 0 5px;
    }

    .label-changed {
      text-decoration: underline;
      text-underline-offset: 5px;
      color: #489ffc;
    }

    .time-no-used {
      opacity: 0.6;
    }
    .current-time {
      color: #67c23a;
      font-weight: bold;
    }
  </style>
</head>

<body>
  <div class="page-container" id="status-watch">
    <div class="page-select">
      <div v-for="item in pageTab" @click="changeTab(item)" :key="item.key" class="select-item"
        :class="item.key === 'status-watch' ? 'active-select': ''">
        {{item.label}}
      </div>
      <img class="login-out" src="../../assets/exit.png" alt="退出登录" title="退出登录" @click="handleLoginOut" />
    </div>
    <div class="iframe-container">
      <div class="page-warp">
        <div class="message" :class="message.type" v-if="message.text">{{message.text}}</div>
        <template v-if="alert.text">
          <div class="dialog-cover alert-dialog-cover"></div>
          <div class="alert-dialog dialog">
            <div class="dialog-title alert-dialog-title">
              提示
            </div>
            <div class="dialog-content">
              {{alert.text}}
            </div>
            <div class="dialog-footer alert-dialog-footer">
              <template v-if="alert.type === MESSAGE_TYPE.ALERT">
                <button class="primary-btn" @click="cancelConfirm">确定</button>
              </template>
              <template v-if="alert.type === MESSAGE_TYPE.CONFIRM">
                <button class="cancel-btn" @click="cancelConfirm">取消</button>
                <button class="primary-btn" @click="handleConfirm(alert)">确定</button>
              </template>
            </div>
          </div>
        </template>
        <div class="edit-content">
          <div>
            <template v-for="item in editList" :key="item.key">
              <button class="primary-btn" @click="handleControl(item)">
                <img src="../../assets/jiazai.png" v-if="loading[item.key]" class="loading" />
                {{item.label}}
              </button>
            </template>
          </div>
        </div>
        <div class="table-content">
          <table border="1">
            <tr>
              <th colspan="4" class="area-title">子区</th>
              <th colspan="13" class="cross-title">路口</th>
            </tr>
            <tr>
              <th class="area-title">子区</th>
              <th class="area-title width-30">运行方案</th>
              <th class="area-title width-30">子区状态</th>
              <th class="area-title width-120">计划时段</th>
              <th class="cross-title">路口</th>
              <!-- <th class="cross-title">控制状态(未)</th> -->
              <th class="cross-title width-30">协调状态</th>
              <th class="cross-title width-30">计划周期</th>
              <th class="cross-title width-30">实时周期</th>
              <!-- <th class="cross-title">需求周期</th> -->
              <th class="cross-title width-45">计划相位差</th>
              <th class="cross-title width-45">实时相位差</th>
              <th class="cross-title width-30">主相位</th>
              <th class="cross-title green-split">实时绿信比</th>
              <th class="cross-title width-30">结婚</th>
              <th class="cross-title width-30">锁方</th>
              <th class="cross-title width-30">锁绿</th>
              <th class="cross-title width-30">锁差</th>
            </tr>
            <template v-for="(item, index) in renderData" :key="item.master">
              <tr class="center" :class="isOdd(item.master) ? 'odd' : 'even'">
                <!-- 子区名称 -->
                <th :rowspan="item.rowNum" v-if="item.isFirst"> {{item.master}} </th>
                <!-- 运行方案 -->
                <td :rowspan="item.rowNum" v-if="item.isFirst">
                  {{item.plan?.plno}}
                </td>
                <!-- 运行状态 -->
                <td :rowspan="item.rowNum" v-if="item.isFirst">
                  <div :class="['checkbox pointer', {'checked': areaStatus[item.master]}]"
                    @click="handleChangeStatus(item)"></div>
                </td>
                <!-- 计划时段 -->
                <td :rowspan="item.rowNum" v-if="item.isFirst">
                  <div>
                    <div v-for="ele in currentAreaTime(item.master)"
                    :class="[{'time-no-used': !ele.enable}, {'current-time': ele.plno == item.plan?.plno && isCurrentTime(ele.time)}]">
                      {{ele.time}}({{ele.plno}})
                    </div>
                  </div>
                </td>
                <!-- 路口 -->
                <th>
                  {{item.site}}
                </th>
                <!-- TODO 未对接 控制状态 -->
                <!-- <td>
                  <div :class="['checkbox circle', {'checkedBlink': false}]"></div>
                </td> -->
                <!-- 协调状态 -->
                <td>
                  <div :class="['checkbox circle', {'checked': isCoordinate(item)}]"></div>
                </td>
                <!-- 计划周期 -->
                <td>
                  {{ item.plan?.cycle }}
                </td>
                <!-- 当前周期 -->
                <td>
                  {{ item.info?.cycle }}
                </td>
                <!-- 计划相位差 -->
                <td>
                  {{ item.plan?.offset }}
                </td>
                <!-- 当前相位差 -->
                <td>
                  {{ item.info?.offset }}
                </td>
                <!-- 主相位 -->
                <td>
                  <template v-if="item.plan?.varph">
                    <{{ item.plan?.varph }}>
                  </template>
                </td>
                <!-- 绿信比 -->
                <td style="text-align: left;">
                  {{ splitInit(item.info?.split) }}
                </td>
                <!-- 结婚 -->
                <td>
                  <div :class="['checkbox circle', {'checked': item.info?.married}]"></div>
                </td>
                <!-- 锁方 -->
                <td>
                  <div :class="['checkbox circle', {'checked': item.info?.lock?.subsys}]"></div>
                </td>
                <!-- 锁绿 -->
                <td>
                  <div :class="['checkbox circle', {'checked': item.info?.lock?.split}]"></div>
                </td>
                <!-- 锁差 -->
                <td>
                  <div :class="['checkbox circle', {'checked': item.info?.lock?.offset}]"></div>
                </td>
              </tr>
            </template>
            <template v-if="!renderData.length">
              <tr class="center">
                <td colspan="17">
                  暂无数据
                </td>
              </tr>
            </template>
            <tr v-if="loading.table">
              <th colspan="15">
                <img src="../../assets/jiazai.png" class="loading" />
              </th>
            </tr>
          </table>
        </div>
        <template v-if="timeConfigData.length">
          <div class="dialog-cover"></div>
          <div class="drawer">
            <div class="drawer-title">
              <div>
                时段控制
              </div>
              <div @click="handleCloseDialog">
                <img src="../../assets/guanbi.png" />
              </div>
            </div>
            <div class="drawer-content">
              <div v-for="(item, index) in timeConfigData" class="time-contorl-content">
                <div class="common-title">子区: {{item.master}}</div>
                <div class="time-item">
                  <template v-for="(time, timeIndex) in item.child">
                    <div :class="['checkbox', {'checked': time.enable}]" @click="time.enable = !time.enable"></div>
                    <!-- {{time.enable}}
                    {{originTimeConfig[index].child[timeIndex].enable}} -->
                    <div
                      :class="['time-show', {'label-changed': time.enable !== originTimeConfig[index]?.child[timeIndex]?.enable}]">
                      {{time.time}}(方案号: {{time.plno}})</div>
                  </template>
                </div>
              </div>
            </div>
            <div class="drawer-footer">
              <button @click="handleCloseDialog" class="cancel-btn">取消</button>
              <button @click="handleSure" class="primary-btn">
                <img src="../../assets/jiazai.png" class="loading" v-if="loading.sure" />
                确认
              </button>
            </div>
          </div>
        </template>
      </div>
    </div>
  </div>

</body>
<script src="../../js/vue3.js"></script>
<script src="../../config.js"></script>
<script src="../../js/api/secondEdition.js"></script>
<script src="../../js/method.js"></script>

<script type="module">
  const { createApp, ref, nextTick, reactive, onMounted, onUpdated, onUnmounted, watch, computed } = Vue
  const app = createApp({
    setup() {

      /** 消息弹窗相关代码 ------------ start ------------ */
      const MESSAGE_TYPE = {
        'SUCCESS': 'success',
        'INFO': 'info',
        'ALERT': 'alert',
        'ERROR': 'error',
        'CONFIRM': 'confirm'
      }

      const message = reactive({
        type: '',
        text: ''
      })

      const alert = reactive({
        type: '',
        text: '',
        methods: null
      })

      // 弹窗消息1.5秒消失
      watch(
        () => message.text,
        () => {
          if (message.text) {
            setTimeout(() => {
              message.text = ''
            }, 1500)
          }
        }
      )
      /** 消息弹窗相关代码 ------------ end ------------ */

      /** 业务相关代码 ------------ start ------------ */

      // const editList1 = [
      //   { key: 'openArea', label: '开启子区', enable: true },
      //   { key: 'closeArea', label: '关闭子区', enable: false },
      //   { key: 'openTime', label: '开启时段', enable: true },
      //   { key: 'closeTime', label: '关闭时段', enable: false },
      // ]

      const editList = [
        { key: 'time', label: '时段控制', enable: true },
        { key: 'open', label: '一键开启', enable: true },
        { key: 'close', label: '一键关闭', enable: false },
      ]
      const currentEditType = ref({})

      // 是否操作区域
      const isArea = computed(() => {
        return currentEditType.value.key.indexOf('Area') > -1
      })


      const subData = ref([]) // 子区数据
      const originData = ref([]) // 接口返回的原始数据
      const renderData = ref([]) // 处理后的数据

      const loading = reactive({
        table: false, // 刷新时段
        sure: false,
        open: false,
        close: false
      })

      // 处理模拟数据
      const apiPreFix = computed(() => {
        return isMock ? '' : apiUrl
      })

      // 处理模拟数据
      const api = computed(() => {
        return isMock ? mockApi : realApi
      })

      // 数据转换
      const initData = () => {
        subData.value = JSON.parse(JSON.stringify(SUB_LIST.value))
        subData.value.forEach(sub => {
          // 需要移除的数据索引值列表
          // let subRemoveList = []
          sub.slave.forEach((site, siteIndex) => {
            // console.log('site', site);

            const result = originData.value.find(item => Number(item.site) === Number(site))
            if (result) {
              sub.slave[siteIndex] = Object.assign(result)
            }
            else {
              // console.log('sub.slave', sub.slave);

              // sub.slave[siteIndex] = Object.assign(sub, {site: site})
            }
            // else {
            //   subRemoveList.push(siteIndex)
            // }
          })
          // 移除接口未返回的数据
          // subRemoveList?.reverse().forEach(ele => {
          //   sub.slave.splice(ele, 1)
          // })
        })
        // 过滤掉空数据
        // subData.value = subData.value.filter(item => item.slave.length)
        // console.log('subData.value', subData.value);
        renderData.value = transformData(subData.value)
      }

      // 获取行的索引值
      const isOdd = computed(() => {
        return (master) => {
          const result = subData.value.findIndex(item => item.master === master)
          return result % 2 === 0
        }
      })

      // 数据合并转换
      const transformData = (originData) => {
        let data = []
        originData?.forEach((element, eleIndex) => {
          element.slave.forEach((item, itemIndex) => {
            data.push({
              ...element,
              ...item,
              site: item.site ?? item,
              isFirst: itemIndex === 0, // 是否子区的第一条数据，第一条数据展示子区
              rowNum: element.slave?.length || 1 // 子区的合并行数
            })
          })
        })
        return data
      }

      // 获取接口返回的数据
      const getInitData = () => {
        fetch(apiPreFix.value + api.value.getWatch).then(res => res.json()).then(res => {
          originData.value = res
          initData()
        })
      }

      // 绿信比转换
      const splitInit = computed(() => {
        return (data) => {
          let result = data
          if (data) {
            result = JSON.stringify(data)?.replace(/"/g, '')?.replace(/{/g, '')?.replace(/}/g, '')?.replace(/,/g, ', ')
          }
          return result
        }
      })
      const cancelConfirm = () => {
        alert.type = ''
        alert.text = ''
        alert.methods = ''
        alert.item = ''
      }

      // 状态发生改变
      const handleChangeStatus = (item) => {
        const status = areaStatus[item.master]
        const type = status ? '关闭' : '开启'
        alert.type = MESSAGE_TYPE.CONFIRM
        alert.text = `确定${type}子区【${item.master}】吗?`
        alert.methods = 'confirmChangeStatus'
        alert.item = item
      }

      // 确定开关子区
      const confirmChangeStatus = (item) => {
        const status = areaStatus[item.master]
        const type = status ? '关闭' : '开启'
        fetch(apiPreFix.value + api.value.setEnableArea, {
          method: 'POST',
          body: JSON.stringify({
            master: item.master,
            enable: !status
          }),
          headers: {
            'content-type': 'application/json'
          }
        })
          .then(res => res.json())
          .then(res => {
            if (!res.err) {
              message.text = `${type}子区【${item.master}】成功`
              message.type = MESSAGE_TYPE.SUCCESS
              getAreaStatus()
            }
            else {
              message.text = res.err || `${type}子区【${item.master}】失败`
              message.type = MESSAGE_TYPE.ERROR
            }
            if (res.code === 401) {
              goLogin()
            }
          })
          .catch((res) => {
            message.text = res.err || `${type}子区【${item.master}】失败`
            message.type = MESSAGE_TYPE.ERROR
          })
      }

      // 确认操作
      const handleConfirm = async (alert) => {
        // console.log('methodsList[key]', methodsList[key]);
        try {
          await methodsList[alert.methods](alert.item)
          cancelConfirm()
        } catch {
          cancelConfirm()
        }
      }

      // 关闭弹窗
      const handleCloseDialog = () => {
        timeConfigData.value = {}
      }

      // 点击弹窗确认
      const handleSure = () => {
        let hasChange = false
        timeConfigData.value.forEach((item, index) => {
          item.child.forEach((ele, eleIndex) => {
            if (ele.enable !== originTimeConfig.value[index]?.child?.[eleIndex].enable) {
              hasChange = true
            }
          })
        })
        if (!hasChange) {
          message.type = MESSAGE_TYPE.ALERT
          message.text = '数据没有修改无需保存'
          return
        }
        alert.type = MESSAGE_TYPE.CONFIRM
        alert.text = '确认保存吗?'
        alert.methods = 'confirmTime'
        alert.item = ''
      }

      const confirmTime = () => {
        loading.sure = true
        let submitData = []
        timeConfigData.value.forEach((item, index) => {
          const isLast = index === timeConfigData.value.length - 1
          saveTime(item, isLast)
        })
      }
      // 保存时段
      const saveTime = (item, isLast = false) => {
        fetch(`${apiPreFix.value}${api.value.setEnableTime}`, {
          method: 'POST',
          body: JSON.stringify(item.child),
          headers: {
            'content-type': 'application/json'
          }
        })
          .then(res => res.json())
          .then(res => {
            if (!isLast) return
            if (!res.err) {
              message.text = `修改成功`
              message.type = MESSAGE_TYPE.SUCCESS
            }
            else {
              message.text = res.err || `修改失败`
              message.type = MESSAGE_TYPE.ERROR
            }
          })
          .catch((res) => {
            message.text = res.err || `修改失败`
            message.type = MESSAGE_TYPE.ERROR
          })
          .finally(() => {
            if (!isLast) return
            loading.sure = false
            getTimeConfig()
            getAreaStatus()
          })
      }

      const handleControl = (item) => {
        if (item.key === 'time') {
          getTimeConfig()
        }
        else {
          alert.type = MESSAGE_TYPE.CONFIRM
          alert.text = `确认【${item.label}】全部配置吗?`
          alert.methods = 'confirmOpenOrClose'
          alert.item = item
        }
      }

      // 一键开启或关闭
      const confirmOpenOrClose = (item) => {
        loading[item.key] = true
        fetch(apiPreFix.value + api.value.enableAll, {
          method: 'POST',
          body: JSON.stringify({
            enable: item.enable
          }),
          headers: {
            'content-type': 'application/json'
          }
        }).then(res => res.json())
          .then(res => {
            if (!res.err) {
              message.text = `${item.label}成功`
              message.type = MESSAGE_TYPE.SUCCESS
              getAreaStatus()
              getTimeConfig(true)
            }
            else {
              message.text = res.err || `${item.label}失败`
              message.type = MESSAGE_TYPE.ERROR
            }
            if (res.code === 401) {
              goLogin()
            }
          })
          .catch((res) => {
            message.text = res.err || `${item.label}失败`
            message.type = MESSAGE_TYPE.ERROR
          })
          .finally((res) => {
            loading[item.key] = false
          })
      }
      /**
       * 协调状态
       * 计划相位差与实时位差相差不大于2
       * 计划周期和实时周期相差不大于2
       * 计划相位差和计划周期的差值 与 实时相位差的差值不大于2
       * 实时相位差和实时周期的差值 与 计划相位差的差值不大于2
       */
      const isCoordinate = computed(() => {
        return (item) => {
          const flag1 = Math.abs(item.plan?.cycle - item.info?.cycle) <= 2
          const flag2 = Math.abs(item.plan?.offset - item.info?.offset) <= 2
          const flag3 = Math.abs(Math.abs(item.plan?.cycle - item.plan?.offset) - item.info?.cycle) <= 2
          const flag4 = Math.abs(Math.abs(item.info?.cycle - item.info?.offset) - item.plan?.cycle) <= 2
          return flag1 && (flag2 || flag3 || flag4)
        }
      })

      // 获取sse推送的实时状态
      const getSSEData = () => {
        const eventSource = new EventSource("/sse/run");
        eventSource.onerror = (err) => console.error(err);
        eventSource.onmessage = (msg) => {
          originData.value = JSON.parse(msg.data)
          initData()
        }
      }

      const areaStatus = reactive({})
      // 获取子区的状态
      const getAreaStatus = () => {
        fetch(apiPreFix.value + api.value.getEnableArea).then(res => res.json()).then(res => {
          res.forEach(item => {
            areaStatus[item.master] = item.enable
          })
        })
      }

      const isControl = ref(true)

      const timeConfigData = ref([])
      const originTimeConfig = ref([])
      const timeShow = ref([])

      // 获取当前子区的时段
      const currentAreaTime = computed(() => {
        return (ssId) => {
          const list = timeShow.value.filter(item => item.master === ssId)
          return list ?? []
        }
      })

      // 获取时段配置
      const getTimeConfig = (flag = false) => {
        fetch(apiPreFix.value + api.value.getEnableTime)
          .then(res => res.json())
          .then(res => {
            timeShow.value = res
            if (flag) {
              return
            }
            timeConfigData.value = JSON.parse(JSON.stringify(SUB_LIST.value))
            timeConfigData.value.forEach(item => item.child = [])
            res.forEach(item => {
              const index = timeConfigData.value.findIndex(ele => ele.master === item.master)
              if (index > -1) {
                timeConfigData.value[index].child.push(item)
              }
            })
            originTimeConfig.value = JSON.parse(JSON.stringify(timeConfigData.value))
          })
      }

      const handleLoginOut = () => {
        alert.text = `确定退出登录吗?`
        alert.type = MESSAGE_TYPE.CONFIRM
        alert.methods = 'goLogin'
      }

      const methodsList = {
        'confirmChangeStatus': confirmChangeStatus,
        'confirmTime': confirmTime,
        'confirmOpenOrClose': confirmOpenOrClose,
        'goLogin': goLogin
      }

      /** 业务相关代码 ------------ end ------------ */
      const timer = ref(null)
      const SUB_LIST = ref([])
      const TIME_LIST = ref([])

      // 是否当前时段
      const isCurrentTime = computed(() => {
        return (time) => {
          const timeList = time.split('-')
          const currentTime = new Date()
          const today = currentTime.getFullYear() + '-' + (currentTime.getMonth() + 1) + '-' + currentTime.getDate()          
          const startTime = new Date(today + ' ' + timeList[0] + ':00')
          const endTime = new Date(today + ' ' + timeList[1] + ':59')
          return startTime <= currentTime && endTime >= currentTime
        }
      })

      onMounted(() => {
        hasLogin(apiPreFix.value)
        const sessionData = JSON.parse(window.sessionStorage.getItem('BASE_DICTS'))
        if (!sessionData) {
          window.location.replace(window.location.origin)
          const currentPage = pageTab.find(item => item.key === 'status-watch')
          currentPage && window.sessionStorage.setItem('CURRENT_PAGE', JSON.stringify(currentPage))
        }
        subData.value = sessionData.areas
        SUB_LIST.value = sessionData.areas
        TIME_LIST.value = sessionData.times
        getInitData()
        getSSEData()
        getAreaStatus()
        getTimeConfig(true)
        // timer.value = setInterval(() => {
        //   getAreaStatus()
        // }, 2000)
      })

      onUnmounted(() => {
        timer.value && clearInterval(timer.value)
      })
      return {
        subData,
        loading,
        message,
        MESSAGE_TYPE,
        renderData,
        editList,
        currentEditType,
        TIME_LIST,
        // isArea,
        isCoordinate,
        areaStatus,
        isControl,
        timeConfigData,
        originTimeConfig,
        currentAreaTime,
        pageTab,
        changeTab,
        isOdd,
        alert,
        isCurrentTime,
        splitInit,
        cancelConfirm,
        handleChangeStatus,
        handleCloseDialog,
        handleSure,
        handleControl,
        handleConfirm,
        handleLoginOut
      }
    }
  })
  app.mount("#status-watch");
</script>

</html>